#!/usr/bin/env bash
# Copyright (c) 2024 maminjie <canpool@163.com>
# SPDX-License-Identifier: MulanPSL-2.0

ROOT_DIR=$(dirname $(readlink -f "$0"))
CUR_DIR=$(pwd)
WORK_DIR=$CUR_DIR/iso_clamscan_workspace

MOUNT_DIR=$WORK_DIR/mount
PKG_DIR=$WORK_DIR/pkg
REPORT_DIR=$WORK_DIR/report

ISO_INFILE=""


usage() {
printf "clamscan iso image

usage:
    bash iso_clamscan.sh [-h] [-i ISO]

optional arguments:
    -i ISO         iso filepath
    -h             show the help message and exit
\n"
}


log_error() {
    echo "ERROR: $1"
}

log_info() {
    echo "INFO: $1"
}


parse_cmdline() {
    if [ $# -eq 0 ]; then
        usage; exit 0
    fi

    # parse cmd line arguments
    while getopts ":i:h" opt; do
        case "$opt" in
            i)
                ISO_INFILE="$OPTARG"
            ;;
            h)
                usage; exit 0
            ;;
            ?)
                echo "please check the params."; usage; return 1
            ;;
        esac
    done
    if [ ! -f "$ISO_INFILE" ]; then
        echo "invalid ISO arguments"; return 1
    fi

    return 0
}

check_user() {
    if [[ $EUID -ne 0 ]]; then
        log_error "This script must be run as root!"
        exit 1
    fi
}

check_requires() {
    local ret=0

    for c in clamscan rpm2cpio mount; do
        command -v $c > /dev/null
        if [ $? -ne 0 ]; then
            log_error "command $c not found"
            ret=1
        fi
    done

    return $ret
}

init_dir() {
    [[ ! -d "$1" ]] && mkdir -p "$1"
}

clean_dir() {
    [[ -d "$1" ]] && rm -rf "$1"
}

do_main() {
    if [ -d "$MOUNT_DIR" ]; then
        umount $MOUNT_DIR 2> /dev/null
    fi
    clean_dir $WORK_DIR

    # init dirs
    init_dir $WORK_DIR
    init_dir $MOUNT_DIR
    init_dir $PKG_DIR
    init_dir $REPORT_DIR

    # mount iso
    mount $ISO_INFILE $MOUNT_DIR &> /dev/null
    if [ $? -ne 0 ]; then
        log_error "mount $ISO_INFILE failed"; return 1
    fi

    # scan iso
    local pkgs=""
    local iso_pkg_dir="$MOUNT_DIR/Packages"
    if [ -d "$iso_pkg_dir" ]; then
        pkgs=$(ls $iso_pkg_dir/*.rpm)
    fi

    local pkg_report_dir="$REPORT_DIR/pkg"
    mkdir -p $pkg_report_dir
    local scan_report_file="$REPORT_DIR/${ISO_INFILE##*/}_clamscan.txt"

    cd $PKG_DIR
    for pkg in $pkgs; do
        local pkg_file=${pkg##*/}
        echo "scanning $pkg_file"
        local pkg_name=$(echo $pkg_file | sed -r 's/-[^-]+-[^-]+$//g')
        local pkg_tmp_dir="$pkg_name"
        mkdir -p $pkg_tmp_dir
        rpm2cpio $pkg | cpio -id --quiet -D $pkg_tmp_dir
        clamscan -r -a -l $pkg_report_dir/${pkg_name}.txt $pkg_tmp_dir &> /dev/null
        if [ $? -eq 0 ]; then
            echo "$pkg_file OK" >> $scan_report_file
        else
            echo "$pkg_file NG" >> $scan_report_file
        fi
        rm -rf $pkg_tmp_dir
    done
    cd $CUR_DIR

    # clean
    umount $MOUNT_DIR 2> /dev/null
    cd $CUR_DIR
    clean_dir $MOUNT_DIR
    clean_dir $PKG_DIR

    return 0
}

main() {
    check_user

    parse_cmdline "$@"
    if [ $? -ne 0 ]; then
        log_error "parse params failed, try -h for help"
        return 1
    fi

    check_requires
    if [ $? -ne 0 ]; then
        log_error "check requires failed"
        return 1
    fi

    do_main
    if [ $? -ne 0 ]; then
        return 1
    fi

    return 0
}

main "$@"
